package wx.wx.service;

import com.baidu.aip.ocr.AipOcr;
import com.thoughtworks.xstream.XStream;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import wx.wx.entity.*;
import wx.wx.util.Utlis;

import javax.print.DocFlavor;
import javax.servlet.ServletInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

import static wx.wx.util.Utlis.doGet;

public class WxService {
    private static final String TOKEN = "zrc";
    //随机笑话
    public static final String URL_C = "http://v.juhe.cn/joke/randJoke.php?key=%s";

    //申请接口的请求key
    // TODO: 您需要改为自己的请求key
    public static final String KEY = "bf27741b26378429de5d30d9867fbd25";
    private static final String GET_TOKEN_URL = " https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    //vx
    private static final String APPID = "wx484f75cacfb7e6e1";
    private static final String APPSECRET = "69a1be806e560b19313555db6217654a";
    //百度ai
    public static final String APP_ID = "24272692";
    public static final String API_KEY = "EydHnquUUfplspdg06joURBw";
    public static final String SECRET_KEY = "pUfFRYo2Yn9NdWIuPAqwj6HM4G6i8wGx";

    //用于存储token
    private static AccessToken at;

    /**
     * 获取token
     */
    private static void getToken() {
        String url = GET_TOKEN_URL.replace("APPID", APPID).replace("APPSECRET", APPSECRET);
        String tokenStr = Utlis.get(url);
        System.out.println(tokenStr);
        JSONObject jsonObject = JSONObject.fromObject(tokenStr);
        String accessToken = jsonObject.getString("access_token");
        String expiresIn = jsonObject.getString("expires_in");
        //创建token对象,并存起来
        at = new AccessToken(accessToken, expiresIn);
    }

    /**
     * 向外暴露获取token的方法
     *
     * @return
     */
    public static String getAccessToken() {
        if (at == null || at.isExpired()) {
            getToken();
        }
        System.out.println("Token:" + at.getAccessToken());
        return at.getAccessToken();
    }

    public static boolean check(String timestamp, String nonce, String signature) {
        //1）将token、timestamp、nonce三个参数进行字典序排序
        String[] strs = new String[]{TOKEN, timestamp, nonce};
        Arrays.sort(strs);
        // 2）将三个参数字符串拼接成一个字符串进行sha1加密
        String str = strs[0] + strs[1] + strs[2];
        String mysig = sha1(str);
        System.out.println(mysig);
        System.out.println(signature);
        // 3）开发者获得加密后的字符串可与signature对比，标识该请求来源于微信
        return mysig.equalsIgnoreCase(signature);
    }

    /**
     * 进行sha1加密
     *
     * @param src
     * @return
     */
    private static String sha1(String src) {

        try {
            //获取一个加密对象
            MessageDigest md = MessageDigest.getInstance("sha1");
            //加密
            byte[] digest = md.digest(src.getBytes());
            char[] chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
            StringBuilder sb = new StringBuilder();
            //处理加密结果
            for (byte b : digest) {
                sb.append(chars[(b >> 4) & 15]);
                sb.append(chars[b & 15]);
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解析xml数据包
     *
     * @param inputStream
     * @return
     */
    public static Map<String, String> parseRequest(ServletInputStream inputStream) {
        Map<String, String> map = new HashMap<>();
        SAXReader reader = new SAXReader();
        try {
            //读取输入流,获取文档对象
            Document document = reader.read(inputStream);
            //根据文档对象获取根节点
            Element root = document.getRootElement();
            //获取根节点的所有子节点
            List<Element> elements = root.elements();
            for (Element e : elements) {
                map.put(e.getName(), e.getStringValue());
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        System.out.println(map);
        return map;
    }

    /**
     * 用于处理所有事件和消息的回复
     *
     * @param requestMap
     * @return 返回的是xml数据包
     */
    public static String getResponse(Map<String, String> requestMap) {
        BaseMessage msg = null;
        String mygType = requestMap.get("MsgType");
        switch (mygType) {
            //处理文本消息
            case "text":
                msg = dealTextMessage(requestMap);
                break;
            case "image":
                msg = dealImageMessage(requestMap);
                break;
            case "voice":

                break;
            case "video":

                break;
            case "shortvideo":

                break;
            case "location":

                break;
            case "link":

                break;
            case "event":
                msg = dealEvent(requestMap);
                break;
            default:

                break;
        }
        //把消息对象处理为xml数据包
        if (msg != null) {
            return beanToXml(msg);
        }
        return null;
    }

    private static BaseMessage dealImageMessage(Map<String, String> requestMap) {

        // 初始化一个AipOcr
        AipOcr client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);

        // 可选：设置网络连接参数
        client.setConnectionTimeoutInMillis(2000);
        client.setSocketTimeoutInMillis(60000);

        // 调用接口
        String path = requestMap.get("PicUrl");
        //识别本地图片的方法
        //org.json.JSONObject res = client.basicGeneral(path, new HashMap<String, String>());
        //识别链接图片的方法
        org.json.JSONObject res = client.generalUrl(path, new HashMap<String, String>());
        System.out.println(res.toString(2));


        String json = res.toString();
        //转为JsonObject
        JSONObject jsonObject = JSONObject.fromObject(json);
        JSONArray jsonArray = jsonObject.getJSONArray("words_result");
        Iterator<JSONObject> iterator = jsonArray.iterator();
        StringBuilder sb = new StringBuilder();
        while (iterator.hasNext()) {
            JSONObject next = iterator.next();
            sb.append(next.getString("words"));
        }

        return new TextMessage(requestMap, sb.toString());
    }

    /**
     * 专门处理事件推送
     *
     * @param requestMap
     * @return
     */
    private static BaseMessage dealEvent(Map<String, String> requestMap) {
        String event = requestMap.get("Event");
        switch (event) {
            case "CLICK":
                return dealClick(requestMap);
            case "View":
                return dealView(requestMap);
            default:
                break;
        }
        return null;
    }

    /**
     * 专门处理view事件
     *
     * @param requestMap
     * @return
     */
    private static BaseMessage dealView(Map<String, String> requestMap) {
        return null;
    }

    /**
     * 专门处理click事件
     *
     * @param requestMap
     */
    private static BaseMessage dealClick(Map<String, String> requestMap) {
        String key = requestMap.get("EventKey");
        switch (key) {
            //点击一级菜单
            case "1":
                return new TextMessage(requestMap, "你点了第一个一级菜单");
            //点击了第三个一级菜单的第二个子菜单
            case "32":
                return new TextMessage(requestMap, "点击了第三个一级菜单的第二个子菜单");
            default:
                break;

        }
        return null;
    }


    private static String beanToXml(BaseMessage msg) {
        XStream stream = new XStream();
        //设置需要处理XStreamAlias("xml")注解的类
        stream.processAnnotations(TextMessage.class);
        stream.processAnnotations(ImageMessage.class);
        stream.processAnnotations(MusicMessage.class);
        stream.processAnnotations(NewsMessage.class);
        stream.processAnnotations(VideoMessage.class);
        stream.processAnnotations(VoiceMessage.class);
        String xml = stream.toXML(msg);
        return xml;
    }

    /**
     * 处理文本消息
     *
     * @param requestMap
     * @return
     */
    private static BaseMessage dealTextMessage(Map<String, String> requestMap) {
        String msg = requestMap.get("Content");
        System.out.println(msg);
        if (msg.equals("图文")) {
            List<Article> articles = new ArrayList<>();
            Article article = new Article("这是图文消息标题", "这是图文消息的详细介绍",
                    "http://mmbiz.qpic.cn/mmbiz_jpg/gxNlgIiaiaWmiaFiactwnv5y12TRYwQLfJqicMgPYibZgBDbUU9clmPnOlSsV8rTFbDSxPDuGyvV5rnur22G7aibTNNPw/0"
                    , "http://www.baidu.com");
            articles.add(article);
            NewsMessage nm = new NewsMessage(requestMap, articles);
            return nm;
        }
        if (msg.equals("登录")) {
            String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx484f75cacfb7e6e1&redirect_uri=http://zhuruochen.viphk.ngrok.org/getUserInfo&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
            TextMessage tm = new TextMessage(requestMap, "点击<a href=\"" + url + "\">这里</a>登陆");
            return tm;
        }
        //调用方法返回聊天的内容
//        String resp = chat(msg);
//        System.out.println(resp);
        TextMessage tm = new TextMessage(requestMap, "您好,有什么可以帮助你");
        return tm;
    }

    /**
     * 调用机器人聊天
     *
     * @param msg 发送的消息
     * @return
     */
    private static String chat(String msg) {
        //发送http请求的url
        String url = String.format(URL_C, KEY);
        final String response = doGet(url);
        System.out.println("接口返回：" + response);
        JSONObject jsonObject = JSONObject.fromObject(response);
        int error_code = jsonObject.getInt("error_code");
        StringBuilder sb = new StringBuilder();
        if (error_code == 0) {
            System.out.println("调用接口成功");
            JSONArray result = jsonObject.getJSONArray("result");
            result.stream().map(JSONObject::fromObject).forEach(hour -> {
                String content = ((JSONObject) hour).getString("content");
                String hashId = ((JSONObject) hour).getString("hashId");
                sb.append(content).append("\r\n").append("\r\n");
            });
        } else {
            System.out.println("调用接口失败：" + jsonObject.getString("reason"));
        }
        return sb.toString();
    }

    /**
     * 上传临时素材
     *
     * @param path 上床文件的路径
     * @param type 上传文件类型
     * @return
     */
    public static String upload(String path, String type) {
        File file = new File(path);
        //地址
        String url = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";
        url = url.replace("ACCESS_TOKEN", getAccessToken());
        url = url.replace("TYPE", type);
        URL urlObj = null;
        try {
            urlObj = new URL(url);
            //强转为安全链接 https
            HttpURLConnection coon = (HttpURLConnection) urlObj.openConnection();
            //设置链接的信息
            coon.setDoInput(true);
            coon.setDoOutput(true);
            coon.setUseCaches(false);
            //设置请求头
            coon.setRequestProperty("Connection", "Keep-Alive");
            coon.setRequestProperty("Charset", "utf8");
            //数据的边界
            String boundary = "----" + System.currentTimeMillis();
            coon.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
            //获取输出流
            OutputStream out = coon.getOutputStream();
            //获取文件输入流
            InputStream is = new FileInputStream(file);
            //第一部分:头部信息
            //准备头部信息
            StringBuilder sb = new StringBuilder();
            sb.append("--");
            sb.append(boundary);
            sb.append("\r\n");
            sb.append("Content-Disposition:form-data;name=\"media\";filename=\"" + file.getName() + "\"\r\n");
            sb.append("Content-Type:application/octet-stream\r\n\r\n");
            out.write(sb.toString().getBytes());
            System.out.println(sb);
            //第二部分:文件内容
            byte[] b = new byte[1024];
            int len;
            while ((len = is.read(b)) != -1) {
                out.write(b, 0, len);
            }
            //第三部分:尾部信息
            String foot = "\r\n--" + boundary + "--\r\n";
            out.write(foot.getBytes());
            out.flush();
            out.close();

            //读取数据
            InputStream is2 = coon.getInputStream();
            StringBuilder resp = new StringBuilder();
            while ((len = is2.read(b)) != -1) {
                resp.append(new String(b, 0, len));
            }
            return resp.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取带参数二维码的ticket
     *
     * @return
     */
    public static String getOrCodeTicket() {
        String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + getAccessToken();
        //生成临时字符串二维码
        String data = "{\"expire_seconds\": 600, \"action_name\": \"QR_STR_SCENE\", \"action_info\": {\"scene\": {\"scene_str\": \"竹若尘\"}}}";
        String resp = Utlis.post(url, data);
        String ticket = JSONObject.fromObject(resp).getString("ticket");
        System.out.println(resp);
        System.out.println(ticket);
        return ticket;
    }

    /**
     * 获取用户信息
     *
     * @return
     */
    public static String getUserInfo(String openId) {
        String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
        url = url.replace("ACCESS_TOKEN", getAccessToken());
        url = url.replace("OPENID", openId);
        System.out.println(url);
        String s = Utlis.get(url);
        return s;
    }

}
